const crypto = require('crypto');
const axios = require('axios');

class WechatOfficialService {
  constructor() {
    this.appId = process.env.WECHAT_OFFICIAL_APPID;
    this.appSecret = process.env.WECHAT_OFFICIAL_SECRET;
    this.token = process.env.WECHAT_OFFICIAL_TOKEN;
    this.accessToken = null;
    this.tokenExpires = 0;

    console.log('初始化微信公众号服务:', {
      appId: this.appId ? this.appId.substring(0, 10) + '...' : '未配置',
      hasSecret: !!this.appSecret,
      token: this.token
    });
  }

  /**
   * 验证微信服务器签名
   * @param {string} signature 微信加密签名
   * @param {string} timestamp 时间戳
   * @param {string} nonce 随机数
   * @returns {boolean} 验证结果
   */
  verifySignature(signature, timestamp, nonce) {
    if (!this.token) {
      console.error('微信公众号Token未配置');
      return false;
    }

    try {
      // 1. 将token、timestamp、nonce三个参数进行字典序排序
      const tmpArr = [this.token, timestamp, nonce].sort();

      // 2. 将三个参数字符串拼接成一个字符串
      const tmpStr = tmpArr.join('');

      // 3. 进行sha1加密
      const hash = crypto.createHash('sha1').update(tmpStr).digest('hex');

      console.log('签名验证:', {
        signature,
        hash,
        timestamp,
        nonce,
        match: hash === signature
      });

      // 4. 开发者获得加密后的字符串可与signature对比，标识该请求来源于微信
      return hash === signature;
    } catch (error) {
      console.error('验证签名失败:', error);
      return false;
    }
  }

  /**
   * 获取access_token
   */
  async getAccessToken() {
    const now = Date.now();
    if (this.accessToken && now < this.tokenExpires) {
      return this.accessToken;
    }

    if (!this.appId || !this.appSecret) {
      throw new Error('微信公众号AppID或AppSecret未配置');
    }

    try {
      const response = await axios.get('https://api.weixin.qq.com/cgi-bin/token', {
        params: {
          grant_type: 'client_credential',
          appid: this.appId,
          secret: this.appSecret
        }
      });

      console.log('获取access_token响应:', response.data);

      if (response.data.access_token) {
        this.accessToken = response.data.access_token;
        this.tokenExpires = now + (response.data.expires_in - 300) * 1000;
        console.log('获取access_token成功, 有效期至:', new Date(this.tokenExpires));
        return this.accessToken;
      } else {
        throw new Error(`获取access_token失败: ${response.data.errmsg}`);
      }
    } catch (error) {
      console.error('获取access_token失败:', error.message);
      throw error;
    }
  }

  /**
   * 获取公众号粉丝资料（包含 unionid）
   * @param {string} openid 公众号 openid
   * @returns {Promise<Object>}
   */
  async fetchOfficialUserProfile(openid) {
    if (!openid) {
      throw new Error('缺少 openid');
    }

    try {
      const accessToken = await this.getAccessToken();
      const response = await axios.get('https://api.weixin.qq.com/cgi-bin/user/info', {
        params: {
          access_token: accessToken,
          openid,
          lang: 'zh_CN'
        }
      });

      console.log('获取公众号粉丝资料:', response.data);

      if (response.data.errcode) {
        throw new Error(`获取公众号粉丝资料失败: ${response.data.errmsg}`);
      }

      return response.data;
    } catch (error) {
      console.error('获取公众号粉丝资料异常:', error.message || error);
      throw error;
    }
  }

  /**
   * 发送模板消息
   */
  async sendTemplateMessage(openid, templateId, data) {
    try {
      const accessToken = await this.getAccessToken();

      const payload = {
        touser: openid,
        template_id: templateId,
        data: data
      };

      // TODO: 暂时注释小程序跳转,等公众号关联小程序后再启用
      // 如果配置了小程序AppID,则添加小程序跳转
      // if (process.env.WECHAT_APP_ID) {
      //   payload.miniprogram = {
      //     appid: process.env.WECHAT_APP_ID,
      //     path: 'pages/chat/chat' // 使用 path 而不是 pagepath,跳转到聊天页面
      //   };
      // }

      console.log('发送模板消息:', { openid, templateId });

      const response = await axios.post(
        `https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${accessToken}`,
        payload
      );

      console.log('模板消息发送响应:', response.data);

      if (response.data.errcode === 0) {
        console.log('模板消息发送成功:', response.data.msgid);
        return { success: true, msgid: response.data.msgid };
      } else {
        console.error('模板消息发送失败:', response.data);
        return { success: false, error: response.data.errmsg };
      }
    } catch (error) {
      console.error('发送模板消息异常:', error.message);
      return { success: false, error: error.message };
    }
  }

  /**
   * 发送挂牌信息提醒
   */
  async sendListingAlert(openid, listing) {
    const templateId = process.env.WECHAT_TEMPLATE_LISTING_ALERT;
    if (!templateId) {
      console.warn('未配置挂牌提醒模板ID');
      return { success: false, error: '未配置模板ID' };
    }

    const data = {
      first: {
        value: `${listing.region}地区发现新的挂牌信息！`,
        color: '#173177'
      },
      keyword1: {
        value: listing.region || '未知地区',
        color: '#FF6B35'
      },
      keyword2: {
        value: listing.category || '未分类',
        color: '#173177'
      },
      keyword3: {
        value: listing.title || '',
        color: '#173177'
      },
      keyword4: {
        value: new Date().toLocaleString('zh-CN'),
        color: '#173177'
      },
      remark: {
        value: '点击查看详情，抢先联系发布者！',
        color: '#008000'
      }
    };

    return await this.sendTemplateMessage(openid, templateId, data);
  }

  /**
   * 发送群聊消息提醒
   * @param {string} openid 用户的公众号openid
   * @param {object} messageData 消息数据
   * @param {string} messageData.senderName 发送者昵称
   * @param {string} messageData.content 消息内容
   * @param {string} messageData.region 地区(可选)
   */
  async sendGroupMessageAlert(openid, messageData) {
    const templateId = process.env.WECHAT_TEMPLATE_GROUP_MESSAGE;
    if (!templateId) {
      console.warn('未配置群聊消息提醒模板ID');
      return { success: false, error: '未配置模板ID' };
    }

    // 截取消息内容,避免过长
    const contentPreview = messageData.content.length > 20
      ? messageData.content.substring(0, 20) + '...'
      : messageData.content;

    // 匹配模板字段: thing1(工单名称), time2(派单时间), thing3(派单区域)
    const data = {
      thing1: {
        value: `${contentPreview || '群友'}发送的消息`,
        color: '#FF6B35'
      },
      time2: {
        value: new Date().toLocaleString('zh-CN', {
          year: 'numeric',
          month: '2-digit',
          day: '2-digit',
          hour: '2-digit',
          minute: '2-digit',
          second: '2-digit'
        }),
        color: '#173177'
      },
      thing3: {
        value: messageData.region || '全国',
        color: '#173177'
      }
    };

    return await this.sendTemplateMessage(openid, templateId, data);
  }

  /**
   * 批量发送群聊消息提醒
   * @param {Array} openidList 公众号openid列表
   * @param {object} messageData 消息数据
   * @returns {object} 发送结果统计
   */
  async batchSendGroupMessageAlert(openidList, messageData) {
    if (!openidList || openidList.length === 0) {
      return {
        success: true,
        total: 0,
        successCount: 0,
        failCount: 0
      };
    }

    console.log(`开始批量发送群聊消息提醒,共${openidList.length}个用户`);

    let successCount = 0;
    let failCount = 0;
    const errors = [];

    // 使用Promise.allSettled并发发送,但限制并发数避免超出微信API限制
    const batchSize = 20; // 每批20个
    for (let i = 0; i < openidList.length; i += batchSize) {
      const batch = openidList.slice(i, i + batchSize);
      const promises = batch.map(openid =>
        this.sendGroupMessageAlert(openid, messageData)
          .then(result => ({ openid, result }))
          .catch(error => ({ openid, error: error.message }))
      );

      const results = await Promise.allSettled(promises);

      results.forEach(result => {
        if (result.status === 'fulfilled' && result.value.result?.success) {
          successCount++;
        } else {
          failCount++;
          if (result.value?.error) {
            errors.push(result.value.error);
          }
        }
      });

      // 批次之间稍作延迟,避免触发微信频率限制
      if (i + batchSize < openidList.length) {
        await new Promise(resolve => setTimeout(resolve, 100));
      }
    }

    console.log(`批量发送完成: 成功${successCount}, 失败${failCount}`);

    return {
      success: true,
      total: openidList.length,
      successCount,
      failCount,
      errors: errors.slice(0, 5) // 只返回前5个错误信息
    };
  }
}

module.exports = new WechatOfficialService();
